﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;

namespace SLGameEngine
{
    public class Engine
    {
        private MapSurface _mapSurface = null;
        private Canvas _parentCanvas = null;
        private Editor _editor;
        private TerrainMgr _terrainMgr;

        public int ScrollSpeed = 5;
        public int ScrollFrameCount = 13;
        public int ScrollDelayInMS = 50;

        private DateTime _lastUpdate = DateTime.Now;
        private Enums.Direction _currentDirection = Enums.Direction.South;


        private ObjectCreature _thisPlayer;
        public ObjectCreature LocalPlayer
        {
            get
            {
                return _thisPlayer;
            }

            private set
            {
                _thisPlayer = value;
            }
        }

        private object _scrollObject = new object();

        public void Initialize(Canvas parentCanvas, List<ObjectBase> templates)
        {
            ObjectMgr.InitializeObjectTemplates(templates);
            _parentCanvas = parentCanvas;
            _mapSurface = new MapSurface();
            _parentCanvas.Children.Add(_mapSurface);

            _terrainMgr = new TerrainMgr(_mapSurface.MainCanvas);
            ObjectCreature creatureObj = (ObjectCreature) ObjectMgr.GetBaseObject(13);
            _thisPlayer = (ObjectCreature) creatureObj.Clone(0);
            _thisPlayer.CurrentY = 0.0;
            _thisPlayer.CurrentY = 0.0;
            _thisPlayer.Animate(Enums.Direction.South, Enums.AnimationType.Idle, true);
            _parentCanvas.Children.Add(_thisPlayer);
        }

        public void ScrollMap(double windowWidth, double windowHeight)
        {
            double elapsedMS = (DateTime.Now - _lastUpdate).TotalMilliseconds;
            if (elapsedMS < ScrollDelayInMS)
                return;

            _lastUpdate = DateTime.Now;

            lock (_scrollObject)
            {
                CenterMap(windowWidth, windowHeight);
                if (_thisPlayer.CurrentX != _thisPlayer.DestX || _thisPlayer.CurrentY != _thisPlayer.DestY)
                    UpdatePosition();
            }
        }

        private void UpdatePosition()
        {
            if (_thisPlayer.CurrentX < _thisPlayer.DestX)
                _thisPlayer.CurrentX += ScrollSpeed;
            else if (_thisPlayer.CurrentX > _thisPlayer.DestX)
                _thisPlayer.CurrentX -= ScrollSpeed;
            if (_thisPlayer.CurrentY < _thisPlayer.DestY)
                _thisPlayer.CurrentY += ScrollSpeed;
            else if (_thisPlayer.CurrentY > _thisPlayer.DestY)
                _thisPlayer.CurrentY -= ScrollSpeed;

            if (true == _thisPlayer.IsAtDest())
                _thisPlayer.Animate(_currentDirection, Enums.AnimationType.Idle, true);
        }

        private void CenterMap(double windowWidth, double windowHeight)
        {
            if (null != _parentCanvas)
            {
                int leftPos = (int) ((windowWidth / 2) - _thisPlayer.CurrentX);
                int topPos = (int) ((windowHeight / 2) - _thisPlayer.CurrentY);

                _parentCanvas.SetValue(Canvas.LeftProperty, (double) leftPos);
                _parentCanvas.SetValue(Canvas.TopProperty, (double)topPos);
            }
        }

        public void ScrollDirection(Enums.Direction direction)
        {
            lock (_scrollObject)
            {
                if (direction == _currentDirection && false == _thisPlayer.IsAtDest())
                    return;

                _currentDirection = direction;

                _thisPlayer.DestX = _thisPlayer.CurrentX;
                _thisPlayer.DestY = _thisPlayer.CurrentY;

                switch (direction)
                {
                    case Enums.Direction.East:
                        _thisPlayer.DestX = _thisPlayer.CurrentX + (ScrollSpeed * ScrollFrameCount);
                        _thisPlayer.Animate(Enums.Direction.East, Enums.AnimationType.Walk, false);
                        break;
                    case Enums.Direction.North:
                        _thisPlayer.DestY = _thisPlayer.CurrentY - (ScrollSpeed * ScrollFrameCount);
                        _thisPlayer.Animate(Enums.Direction.North, Enums.AnimationType.Walk, false);
                        break;
                    case Enums.Direction.West:
                        _thisPlayer.DestX = _thisPlayer.CurrentX - (ScrollSpeed * ScrollFrameCount);
                        _thisPlayer.Animate(Enums.Direction.West, Enums.AnimationType.Walk, false);
                        break;
                    case Enums.Direction.South:
                        _thisPlayer.DestY = _thisPlayer.CurrentY + (ScrollSpeed * ScrollFrameCount);
                        _thisPlayer.Animate(Enums.Direction.South, Enums.AnimationType.Walk, false);
                        break;
                    case Enums.Direction.SE:
                        _thisPlayer.DestY = _thisPlayer.CurrentY + (ScrollSpeed * ScrollFrameCount);
                        _thisPlayer.DestX = _thisPlayer.CurrentX + (ScrollSpeed * ScrollFrameCount);
                        _thisPlayer.Animate(Enums.Direction.SE, Enums.AnimationType.Walk, false);
                        break;
                    case Enums.Direction.NE:
                        _thisPlayer.DestY = _thisPlayer.CurrentY - (ScrollSpeed * ScrollFrameCount);
                        _thisPlayer.DestX = _thisPlayer.CurrentX + (ScrollSpeed * ScrollFrameCount);
                        _thisPlayer.Animate(Enums.Direction.NE, Enums.AnimationType.Walk, false);
                        break;
                    case Enums.Direction.SW:
                        _thisPlayer.DestX = _thisPlayer.CurrentX - (ScrollSpeed * ScrollFrameCount);
                        _thisPlayer.DestY = _thisPlayer.CurrentY + (ScrollSpeed * ScrollFrameCount);
                        _thisPlayer.Animate(Enums.Direction.SW, Enums.AnimationType.Walk, false);
                        break;
                    case Enums.Direction.NW:
                        _thisPlayer.DestY = _thisPlayer.CurrentY - (ScrollSpeed * ScrollFrameCount);
                        _thisPlayer.DestX = _thisPlayer.CurrentX - (ScrollSpeed * ScrollFrameCount);
                        _thisPlayer.Animate(Enums.Direction.NW, Enums.AnimationType.Walk, false);
                        break;
                }
            }
        }

        public Editor GetEditor()
        {
            if (null == _editor)
                _editor = new Editor(_mapSurface.MainCanvas, _terrainMgr);

            return _editor;
        }

        public TerrainMgr GetTerrainMgr()
        {
            return _terrainMgr;
        }
    }
}
